package com.gitee.qdbp.jdbc.stream;

import java.io.Serializable;
import java.util.Arrays;
import java.util.Collection;
import java.util.Map;
import com.gitee.qdbp.able.enums.LogicType;
import com.gitee.qdbp.able.exception.ServiceException;
import com.gitee.qdbp.able.jdbc.condition.DbUpdate;
import com.gitee.qdbp.able.jdbc.condition.DbWhere;
import com.gitee.qdbp.able.jdbc.condition.DbWhereForFieldCore;
import com.gitee.qdbp.able.jdbc.condition.DbWhereForOnFieldless;
import com.gitee.qdbp.able.jdbc.condition.DbWhereForStartCore;
import com.gitee.qdbp.able.jdbc.condition.SkipType;
import com.gitee.qdbp.jdbc.api.CrudDao;
import com.gitee.qdbp.jdbc.exception.DbErrorCode;
import com.gitee.qdbp.jdbc.model.SimpleFieldColumn;
import com.gitee.qdbp.jdbc.utils.ParseTools;
import com.gitee.qdbp.tools.utils.VerifyTools;

/**
 * UdateSet后续操作<br>
 * where / update
 * 
 * @author zhaohuihua
 * @version 20210530
 */
public class CrudOnAfterSetByStream<T> {

    protected final CrudDao<T> dao;
    protected final DbUpdate ud;

    CrudOnAfterSetByStream(CrudDao<T> dao, DbUpdate ud) {
        this.dao = dao;
        this.ud = ud;
    }

    /**
     * Where条件<br>
     * <pre>
    int rows = qdbcBoot.crudStream(SysUser.class)
        .updateSet("userName").to("zhaohuihua") // 用户名修改为指定值
            .set("memberScore").add(+100) // 会员积分增加100
            .set("memberScore").add(-100) // 会员积分减少100
            .set("userState").toNull() // 用户状态修改为空
            .end()
        .where("userId").equals("U0000001")
            .and("userState").in(UserState.NORMAL, UserState.LOCKED)
            .end()
        .update();
     * </pre>
     * 
     * @param fieldName 字段名称
     * @return 返回后续流式操作对象
     */
    public DbWhereForFieldCore<CrudOnUpdateWhereByStream<T>> where(String fieldName) {
        DbWhere where = DbWhere.newEmptiableWhere();
        CrudOnUpdateWhereByStream<T> next = new CrudOnUpdateWhereByStream<>(dao, ud, where);
        DbWhereForStartCore<CrudOnUpdateWhereByStream<T>> start = new DbWhereForStartCore<>(next, where);
        return new DbWhereForFieldCore<>(start, SkipType.NONE, LogicType.AND, fieldName);
    }

    /**
     * 查询条件<br>
     * <pre>
    int rows = qdbcBoot.crudStream(SysUser.class)
        .updateSet("userName").to("zhaohuihua") // 用户名修改为指定值
            .set("memberScore").add(+100) // 会员积分增加100
            .set("memberScore").add(-100) // 会员积分减少100
            .set("userState").toNull() // 用户状态修改为空
            .end()
        .where().subCondition((w) -> {
                w.on("userCode").like("test")
                 .or("realName").like("test");
            })
            .and("userState").in(UserState.NORMAL, UserState.LOCKED)
            .end()
        .update();
     * </pre>
     * 
     * @return 返回后续流式操作对象
     */
    public DbWhereForOnFieldless<CrudOnUpdateWhereByStream<T>> where() {
        DbWhere where = DbWhere.newEmptiableWhere();
        CrudOnUpdateWhereByStream<T> next = new CrudOnUpdateWhereByStream<>(dao, ud, where);
        DbWhereForStartCore<CrudOnUpdateWhereByStream<T>> start = new DbWhereForStartCore<>(next, where);
        return new DbWhereForOnFieldless<>(start, SkipType.NONE);
    }

    /**
     * 设置Where条件
     * 
     * @param where Where条件
     * @return 返回后续流式操作对象
     */
    public CrudOnUpdateWhereByStream<T> whereBy(DbWhere where) {
        return new CrudOnUpdateWhereByStream<>(dao, ud, where);
    }

    /**
     * 从实体类构建Where对象<br>
     * <pre>
    int rows = qdbcBoot.crudStream(SysUser.class)
        .updateSet("userName").to("zhaohuihua") // 用户名修改为指定值
            .set("memberScore").add(+100) // 会员积分增加100
            .set("memberScore").add(-100) // 会员积分减少100
            .set("userState").toNull() // 用户状态修改为空
            .end()
        .whereBy(user)
        .update();
     * </pre>
     * 
     * @param entity 实体类
     * @return 返回后续流式操作对象
     * @see ParseTools#parseBeanToDbWhere(Object)
     */
    public CrudOnUpdateWhereByStream<T> whereBy(T entity) {
        DbWhere where = dao.plugins().parseTools().parseBeanToDbWhere(entity);
        return new CrudOnUpdateWhereByStream<>(dao, ud, where);
    }

    /**
     * 从Map构建Where对象<br>
     * <pre>
    int rows = qdbcBoot.crudStream(SysUser.class)
        .updateSet("userName").to("zhaohuihua") // 用户名修改为指定值
            .set("memberScore").add(+100) // 会员积分增加100
            .set("memberScore").add(-100) // 会员积分减少100
            .set("userState").toNull() // 用户状态修改为空
            .end()
        .whereBy(map)
        .update();
     * </pre><br>
     * 只会包含clazz注解中通过@Column指定的字段名<br>
     * 应注意, 此时参数由前端传入, 条件不可控, 也有可能条件为空, 需要仔细检查条件内容, 防止越权操作 <pre>
     * 转换规则:
        fieldName$Equals(=), fieldName$NotEquals(!=), 
        fieldName$LessThen(<), fieldName$LessEqualsThen(<=), 
        fieldName$GreaterThen(>), fieldName$GreaterEqualsThen(>=), 
        fieldName$IsNull, fieldName$IsNotNull, 
        fieldName$Like, fieldName$NotLike, fieldName$Starts, fieldName$Ends, 
        fieldName$In, fieldName$NotIn, fieldName$Between
     * </pre>
     * 
     * @param map Map参数
     * @return 返回后续流式操作对象
     * @see ParseTools#parseBeanToDbWhere(Object)
     */
    public CrudOnUpdateWhereByStream<T> whereBy(Map<String, Object> map) {
        DbWhere where = dao.plugins().parseTools().parseBeanToDbWhere(map);
        return new CrudOnUpdateWhereByStream<>(dao, ud, where);
    }

    /**
     * 以ID作为条件更新<br>
     * <pre>
    int rows = qdbcBoot.crudStream(SysUser.class)
        .entity(user)
        .whereById("U0000001")
        .update();
     * </pre>
     * 
     * @param id 实体主键
     * @return 返回后续流式操作对象
     */
    public CrudOnUpdateWhereByStream<T> whereById(Serializable id) {
        VerifyTools.requireNotBlank(id, "id");
        SimpleFieldColumn pk = dao.sqlHelper().fragment().getPrimaryKey();
        if (pk == null) { // 没有找到主键字段
            String details = "UnsupportedWhereById, class=" + dao.getBeanClass().getName();
            throw new ServiceException(DbErrorCode.DB_PRIMARY_KEY_FIELD_IS_UNRESOLVED, details);
        }
        String primaryField = pk.getFieldName();
        DbWhere where = DbWhere.newEmptiableWhere();
        where.on(primaryField).equals(id);
        return new CrudOnUpdateWhereByStream<>(dao, ud, where);
    }

    /**
     * 按ID列表查询<br>
     * <pre>
    int rows = qdbcBoot.crudStream(SysUser.class)
        .updateSet("userName").to("zhaohuihua") // 用户名修改为指定值
            .set("memberScore").add(+100) // 会员积分增加100
            .set("memberScore").add(-100) // 会员积分减少100
            .set("userState").toNull() // 用户状态修改为空
            .end()
        .whereByIds("U0000001", "U0000002", ...)
        .update();
     * </pre>
     * 
     * @param ids 主键列表
     * @return 返回后续流式操作对象
     */
    public CrudOnUpdateWhereByStream<T> whereByIds(String... ids) {
        VerifyTools.requireNotBlank(ids, "ids");
        return doWhereByIds(Arrays.asList(ids));
    }

    /**
     * 以ID列表作为条件更新<br>
     * <pre>
    int rows = qdbcBoot.crudStream(SysUser.class)
        .updateSet("userName").to("zhaohuihua") // 用户名修改为指定值
            .set("memberScore").add(+100) // 会员积分增加100
            .set("memberScore").add(-100) // 会员积分减少100
            .set("userState").toNull() // 用户状态修改为空
            .end()
        .whereByIds("U0000001", "U0000002", ...)
        .update();
     * </pre>
     * 
     * @param ids 主键列表
     * @return 返回后续流式操作对象
     */
    public CrudOnUpdateWhereByStream<T> whereByIds(Collection<? extends Serializable> ids) {
        VerifyTools.requireNotBlank(ids, "ids");
        return doWhereByIds(ids);
    }

    protected CrudOnUpdateWhereByStream<T> doWhereByIds(Collection<? extends Serializable> ids) {
        SimpleFieldColumn pk = dao.sqlHelper().fragment().getPrimaryKey();
        if (pk == null) { // 没有找到主键字段
            String details = "UnsupportedWhereByIds, class=" + dao.getBeanClass().getName();
            throw new ServiceException(DbErrorCode.DB_PRIMARY_KEY_FIELD_IS_UNRESOLVED, details);
        }
        String primaryField = pk.getFieldName();
        DbWhere where = DbWhere.newEmptiableWhere();
        where.on(primaryField).in(ids);
        return new CrudOnUpdateWhereByStream<>(dao, ud, where);
    }
}
